﻿using System;
using Beaker;
using Beaker.Specs;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenCube.Nbt.Mapping;
using OpenCube.Nbt.Mapping.Attributes;
using OpenCube.Nbt.Specs.Builders;

namespace OpenCube.Nbt.Specs
{
	[TestClass]
	internal sealed class MappingSpecs
		: SpecsFor<NbtMapper<TestModel>, NbtMapperBuilder<TestModel>>
	{
		[TestMethod]
		public void NbtMapsByExactPropertyName()
		{
			var dictionary = new NbtDictionary
			{
				 { "Integer", 31415 }
			};

			TestModel model = Subject.MapToModel(dictionary);

			model.Integer.Should().Be(31415);
		}

		[TestMethod]
		public void NbtNameAltersExpectedNameInDictionary()
		{
			var dictionary = new NbtDictionary
			{
				{ "foo-bar", "Chocolate" }
			};

			TestModel model = Subject.MapToModel(dictionary);

			model.FooBar.Should().Be("Chocolate");
		}

		[TestMethod]
		public void NbtConverterUsesTheConverterToAlterTheData()
		{
			var dictionary = new NbtDictionary
			{
				{ "with-converter", "cookies" }
			};

			TestModel model = Subject.MapToModel(dictionary);

			model.WithConverter.Should().Be(TestEnum.Cookies);
		}

		#region build in conversions

		[TestMethod]
		public void SByteBoolIsABuildInConversion()
		{
			var dictionary = new NbtDictionary
			{
				{ "boolean", (sbyte)1 }
			};

			TestModel model = Subject.MapToModel(dictionary);

			model.IsBoolean.Should().BeTrue();
		}

		#endregion

	}

	internal sealed class TestModel
	{
		[Nbt]
		public int Integer { get; set; }

		[NbtName("foo-bar")]
		public string FooBar { get; set; }

		[NbtName("with-converter")]
		[NbtConverter(typeof(TestConverter))]
		public TestEnum WithConverter { get; set; }

		[NbtName("boolean")]
		public bool IsBoolean { get; set; }
	}

	internal enum TestEnum
	{
		None,
		Cookies,
		Milk
	}

	internal sealed class TestConverter
		: NbtSimpleTypeConverter<TestEnum, string>
	{
		protected override TestEnum ConvertToModelValue(string nbtValue)
		{
			switch (nbtValue)
			{
				case "cookies":
					return TestEnum.Cookies;
				case "milk":
					return TestEnum.Milk;
			}

			throw new NotSupportedException();
		}

		protected override Maybe<string> ConvertToNbtValue(TestEnum modelValue)
		{
			throw new NotImplementedException();
		}
	}
}
